#pragma once
#include <map>
#include <vector>
#include <string>
#include <set>
#include <iterator>
#if (defined(__clang__) && defined(_LIBCPP_VERSION)) || (__cplusplus >= 201103L)
#include <memory>
#else
#include <tr1/memory>
#endif
#include <curl/curl.h>
#ifdef USE_LUA
#include <lua.hpp>
#endif

class BBS2chProxyHttpHeadersIterator;

class BBS2chProxyHttpHeaderEntry {
	friend class BBS2chProxyHttpHeadersIterator;
private:
	std::string _name;
	std::vector<std::string> _values;
public:
	BBS2chProxyHttpHeaderEntry(const std::string &name, const std::string &value)
	{
		_name = name;
		_values.push_back(value);
	};
	const std::string& getName(void);
	std::string getLowercasedName(void);
	std::string getValue(void);
	std::string getFull(bool shouldIncludeLineBreak=false);
	std::vector<std::string>& getValueList(void);
	void add(const std::string &value);
	void set(const std::string &value);
	bool has(const std::string &value);
	bool contains(const std::string &value);
	void replaceValue(const std::string &from, const std::string &to);
};

#if (defined(__clang__) && defined(_LIBCPP_VERSION)) || (__cplusplus >= 201103L)
typedef std::shared_ptr<BBS2chProxyHttpHeaderEntry> PBBS2chProxyHttpHeaderEntry;
#else
typedef std::tr1::shared_ptr<BBS2chProxyHttpHeaderEntry> PBBS2chProxyHttpHeaderEntry;
#endif


class BBS2chProxyHttpHeaders {
	friend class BBS2chProxyHttpHeadersIterator;
private:
	std::map<std::string, PBBS2chProxyHttpHeaderEntry> _headers;
	std::string _statusLine;
public:
	typedef BBS2chProxyHttpHeadersIterator iterator;
	std::string get(const std::string &name);
	std::string getFull(const std::string &name, bool shouldIncludeLineBreak=false);
	PBBS2chProxyHttpHeaderEntry getEntry(const std::string &name);
	bool has(const std::string &name);
	bool hasNameAndValue(const std::string &name, const std::string &value);
	void add(const std::string &name, const std::string &value);
	void add(const char *field);
	void add(const char *field, size_t length);
	void set(const std::string &name, const std::string &value);
	void set(PBBS2chProxyHttpHeaderEntry entry);
	void remove(const std::string &name);
	void clear(void);
	const std::string& getStatusLine();
	void setStatusLine(const char *field, size_t length);
	curl_slist* appendToCurlSlist(curl_slist *list, const std::set<std::string> &excludes = std::set<std::string>());
	curl_slist* appendToCurlSlist(curl_slist *list, const std::string &name);
	std::map<std::string, PBBS2chProxyHttpHeaderEntry>& getMap(void);
	bool empty();
	BBS2chProxyHttpHeaders::iterator begin();
	BBS2chProxyHttpHeaders::iterator end();
	static PBBS2chProxyHttpHeaderEntry parse(const char *field, size_t length);
#ifdef USE_LUA
	static void getObjectMetatableForLua(lua_State *l);
	static void getClassDefinitionForLua(lua_State *l);
	void getUserdataForLua(lua_State *l);
#endif
};

class BBS2chProxyHttpHeadersIterator {
	friend class BBS2chProxyHttpHeaders;
	std::pair<PBBS2chProxyHttpHeaderEntry, std::string> _value;
	std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator _mapIterator;
	std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator _mapIteratorEnd;
	std::vector<std::string>::iterator _vectorIterator;
	BBS2chProxyHttpHeadersIterator() {/* never used */};
	BBS2chProxyHttpHeadersIterator(BBS2chProxyHttpHeaders* headers, bool firstOrLast);
public:
	typedef std::forward_iterator_tag iterator_categoly;
	typedef std::pair<PBBS2chProxyHttpHeaderEntry, std::string> value_type;
	typedef value_type* pointer;
	typedef value_type& reference;
	typedef ptrdiff_t difference_type; /* not implemented */
	BBS2chProxyHttpHeadersIterator& operator++();
	BBS2chProxyHttpHeadersIterator operator++(int);
	reference operator*();
	pointer operator->();
	bool operator==(const BBS2chProxyHttpHeadersIterator& iterator);
	bool operator!=(const BBS2chProxyHttpHeadersIterator& iterator);
};
